package org.lyfeng.spring.context.annotation;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.LinkedHashSet;
import java.util.Set;

import org.lyfeng.spring.aop.AspectRegister;
import org.lyfeng.spring.aop.annotation.Aspect;
import org.lyfeng.spring.beans.annotation.Autowired;
import org.lyfeng.spring.beans.definitions.AopAutowireBeanDefinition;
import org.lyfeng.spring.beans.definitions.AutowireBeanDefinition;
import org.lyfeng.spring.beans.definitions.BeanDefinition;
import org.lyfeng.spring.beans.definitions.BeanDefinitionRegistry;
import org.lyfeng.spring.beans.factory.config.SingletonBeanRegistry;
import org.lyfeng.spring.beans.factory.support.AbstractBeanFactory;
import org.springframework.util.ClassUtils;

/**
 * 类加载和注解解析器
 * @author leiyufeng
 * 2013-4-24 下午4:50:44
 */
public class ClassPathBeanDefinitionScanner implements Scanner{
//	private SingletonBeanRegistry register;
	private BeanDefinitionRegistry beanDefinitionRegister;
	private SingletonBeanRegistry beanRegister;
	private AspectRegister aspectRegister;
	public ClassPathBeanDefinitionScanner(AbstractBeanFactory register) {
		// TODO Auto-generated constructor stub
		this.beanDefinitionRegister=register;
		this.beanRegister=register;
		this.aspectRegister=register;
	}
	@Override
	public void scan(ClassLoader classLoader,String... packages) {
		for(String s:packages)
		{
			findCandidateComponents(classLoader, s);
		}
	}
	@Override
	public Set<BeanDefinition> findCandidateComponents(ClassLoader classLoader,String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
		String packageSearchPath=resolveBasepackage(basePackage);
		URL url=classLoader.getResource(packageSearchPath);
		File file=new File(url.getPath());
		File[] files=file.listFiles();
		for(File f:files)
		{
			try {
				if (f.isDirectory()) {
					findCandidateComponents(classLoader, basePackage+"."+f.getName());
				} else {
					StringBuilder sb = new StringBuilder();
					sb.append(packageSearchPath);
					sb.append("/");
					sb.append(f.getName());
					String classPath = sb.toString().split("\\.")[0];

					classPath = classPath.replaceAll("/", ".");
					Class<?> tempClass = classLoader.loadClass(classPath);

					Annotation[] annotations = tempClass.getAnnotations();
					if (null == annotations || 0 == annotations.length)
						continue;
					if (annotations.length > 1) {
						System.out.println("目前只支持一个标注");
						throw new RuntimeException("目前只支持一种标注");
					}
					Annotation annotation = annotations[0];
					if (annotation instanceof Component) {
						BeanDefinition beanDefinition = resolveComponentAnnotation(
								tempClass, (Component) annotation);
						candidates.add(beanDefinition);
					} else if (annotation instanceof Aspect) {
						resolveAspectAnnotation(tempClass, (Aspect) annotation);
					}
				}
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println(e.getCause());
			}
		}
		return candidates;
	}
	protected BeanDefinition resolveComponentAnnotation(Class<?> clazz,Component component)
	{
		String beanName=component.name();//bean name
		AutowireBeanDefinition beanDefinition=new AutowireBeanDefinition();
		beanDefinition.setBeanName(beanName);
		beanDefinition.setClassName(clazz.getName());
		beanDefinition.setResolvedClass(clazz);
		//添加自动注入的propertie
		Field[] fields=clazz.getDeclaredFields();
		for(Field field:fields)
		{
			if(null!=field.getAnnotation(Autowired.class))
			{
//				field.setAccessible(true);
				beanDefinition.addProperty(field.getName(), field.getType().getName());
				beanRegister.registerDependentBean(beanName, field.getName());
			}
		}
		beanDefinitionRegister.registerBeanDefinition(beanName, beanDefinition);
		return beanDefinition;
	}
	/**
	 * 注册所有的aspect
	 * @param clazz
	 * @param aspect
	 */
	protected void resolveAspectAnnotation(Class<?> clazz,Aspect aspect)
	{
//		String _package=aspect._package();
		aspectRegister.registerAspect(clazz);
		AopAutowireBeanDefinition beanDefinition=new AopAutowireBeanDefinition();
		beanDefinition.setBeanName(aspect.name());
		beanDefinition.setClassName(clazz.getName());
		beanDefinition.setResolvedClass(clazz);
		beanDefinition.setPattern(aspect._package());
		aspectRegister.registerBeanDefinition(beanDefinition);
	}
	protected String resolveBasepackage(String basePackage)
	{
		return ClassUtils.convertClassNameToResourcePath(basePackage);
	}
}
